package com.base.monitor.module.biz.service.cfg.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.base.monitor.framework.exception.CustomerException;
import com.base.monitor.framework.result.Result;
import com.base.monitor.framework.util.JsonUtils;
import com.base.monitor.model.constant.CfgConstant;
import com.base.monitor.model.enums.code.impl.common.MicroServiceCode;
import com.base.monitor.model.model.biz.cfg.entity.Gateway;
import com.base.monitor.model.model.biz.cfg.entity.Indicator;
import com.base.monitor.model.model.biz.cfg.vo.*;
import com.base.monitor.module.biz.context.CfgContext;
import com.base.monitor.module.biz.properties.ParamProperties;
import com.base.monitor.module.biz.service.cfg.InteractionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * @description:
 * @author: tsing
 * @create: 2021-06-17 21:56
 */
@Service
@Slf4j
@EnableConfigurationProperties(ParamProperties.class)
public class InteractionServiceImpl implements InteractionService {

    @Autowired
    private ParamProperties paramProperties;

    @Autowired
    private RestTemplate restTemplate;

    // TODO 开发时用
    @Value("classpath:json/brightSky.json")
    private Resource resource;

    static Map<Long, Gateway> gatewayVoMap = new HashMap<>();

    @PostConstruct
    public void init() {
        syncAllInfoFromRemote();
    }

    /**
     * 从基础监控管理系统中获取所有指标、设备和网关的信息
     *
     * @return
     */
    @Override
    public synchronized void syncAllInfoFromRemote() {
        try {
            // 1.清空数据
            clearCacheData();

            // 2.获取数据
            // TODO 开发从json文件中获取
//          List<IndicatorDeviceGatewayVo> list = getAllInfoFromRemote();
            List<IndicatorDeviceGatewayVo> list = JsonUtils.getListDataFromResultJson(resource, IndicatorDeviceGatewayVo.class);

            // 3.将数据解析成GatewayVo
            parseGatewayVo(list);

            // 4.将数据解析成IndicatorAllVo
            parseIndicatorAllVo(list);

            log.info("远端获取数据成功");
        } catch (Exception e) {
            log.error("远端获取数据失败，原因是：{}", e.getMessage(), e);
        }

    }



    /**
     * 将数据解析成IndicatorAllVo
     * @param list 待解析的数据
     */
    private void parseIndicatorAllVo(List<IndicatorDeviceGatewayVo> list) {
        if (CollectionUtil.isEmpty(list)) {
            return;
        }

        List<Indicator> indicators = new ArrayList<>();
        for (IndicatorDeviceGatewayVo rawVo : list) {
            Indicator vo = new Indicator(rawVo);
            indicators.add(vo);
        }

        CfgContext.addIndicatorAllVoList(indicators);
    }



    /**
     * 将数据解析成GatewayVo
     * @param list 待解析的数据
     */
    private void parseGatewayVo(List<IndicatorDeviceGatewayVo> list) {
        if (CollectionUtil.isEmpty(list)) {
            return;
        }

        for (IndicatorDeviceGatewayVo rawVo : list) {
            // 1.处理网关信息
            Gateway gateway = getGatewayVo(rawVo);

            // 2.处理指标信息
            dealWithIndicator(rawVo, gateway);

            // 3.回写缓存信息
            writeBackForCache(gateway);
        }

        CfgContext.addGatewayVoList(new ArrayList<>(gatewayVoMap.values()));
    }

    /**
     * 回写缓存信息
     * @param gateway 解析出来的网关信息
     */
    private void writeBackForCache(Gateway gateway) {
        boolean send = true;
        for (IndicatorCommandVo indicator : gateway.getIndicators()) {
            if (indicator.getFrequency() != null
                    && indicator.getFrequency().equals(CfgConstant.NEED_NOT_SEND)) {
                send = false;
                break;
            }
        }
        gateway.setCount(gateway.getIndicators().size());
        gateway.setNeedSend(send);
        gatewayVoMap.put(gateway.getGatewayId(), gateway);
    }

    /**
     * 从远端信息中获取指标信息
     * @param rawVo 远端信息
     * @param gateway 解析出来的网关
     */
    private void dealWithIndicator(IndicatorDeviceGatewayVo rawVo, Gateway gateway) {
        IndicatorCommandVo vo = new IndicatorCommandVo(rawVo);
        gateway.getIndicators().add(vo);
    }

    /**
     * 从远端的信息中获取网关信息
     * @param rawVo 远端的信息
     * @return
     */
    private Gateway getGatewayVo(IndicatorDeviceGatewayVo rawVo) {
        Long gatewayId = rawVo.getGatewayId();
        Gateway gateway = gatewayVoMap.get(gatewayId);
        if (gateway == null) {
            gateway = new Gateway(rawVo);
            gateway.setStatus(CfgConstant.STATUS_IS_OFFLINE);
        }
        return gateway;
    }

    /**
     * 从远端获取所有的数据
     * @return
     */
    private List<IndicatorDeviceGatewayVo> getAllInfoFromRemote() {
        String allDeviceInfoUrl = paramProperties.getAllDeviceInfoUrl();
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", "application/json");
        HttpEntity entity = new HttpEntity(headers);
        ParameterizedTypeReference<Result<List<IndicatorDeviceGatewayVo>>> responseType = new ParameterizedTypeReference<Result<List<IndicatorDeviceGatewayVo>>>() {};
        ResponseEntity<Result<List<IndicatorDeviceGatewayVo>>> resp;
        try {
            resp = restTemplate.exchange(allDeviceInfoUrl, HttpMethod.GET, entity, responseType);
        } catch (Exception e) {
            throw new CustomerException(MicroServiceCode.INVOKING_FAILURE, "调用资产系统失败，原因是：" + e.getMessage());
        }
        Result result = resp.getBody();
        if (result == null || result.getCode() != 1) {
            throw new CustomerException(MicroServiceCode.INVOKING_FAILURE, "调用资产系统失败，原因是：" + result.getMessage());
        }
        return (List<IndicatorDeviceGatewayVo>) result.getData();
    }

    /**
     * 清除缓存数据
     */
    private void clearCacheData() {
        gatewayVoMap.clear();
        CfgContext.clearGatewayVoList();
        CfgContext.clearIndicatorAllVoList();
    }
}
